//
//  TNImageEditingView.swift
//  TNImageEditing
//
//  Created by Name i on 2021/12/20.
//

import UIKit

class NNEditingInfoModel: NSObject {
    
    // 标记内容为图片还是文字 
    var isContentImage: Bool = false
    
    // 如果内容为图片：此属性不能为空：记录原始图片,
    var originalImage: UIImage?
    // 如果内容为文字：此属性不能为空：记录原始文字字符串及其Attributes
    var originalText: NSAttributedString?
    
    // 真正显示的图片：如果isContentImage为true，则为originalText合成的图片，否则则为originalImage
    var contentImage: UIImage?
    
    // contentImage的size 第一次显示的时候的尺寸，即原始尺寸，如果编辑后需要还原，则通过该尺寸*scale
    var originalSize: CGSize = .zero
    
    // 视图的中心位置
    var center: CGPoint = .zero
    
    // 默认为1.0
    var scale: CGFloat = 1.0
}





let kControlWH: CGFloat = 24.0

class NNEditingImageView: UIView {
    
    private lazy var imageView: UIImageView = {
        let img = UIImageView(frame: CGRect(x: kControlWH * 0.5,
                                            y: kControlWH * 0.5,
                                            width: frame.size.width - kControlWH,
                                            height: frame.size.height - kControlWH))
        img.contentMode = .scaleAspectFit
        img.clipsToBounds = true
        return img
    }()
    private lazy var rotateCtrl: UIImageView = {
        let img = UIImageView(frame: CGRect(x: frame.size.width - kControlWH,
                                            y: frame.size.height - kControlWH,
                                            width: kControlWH,
                                            height: kControlWH))
        img.image = UIImage(named: "AddView_rotate")
        img.isUserInteractionEnabled = true
        img.addGestureRecognizer(UIPanGestureRecognizer(target: self,
                                                        action: #selector(rotateControlAction(sender:))))
        return img
    }()
    private lazy var removeCtrl: UIImageView = {
        let img = UIImageView(frame: CGRect(x: 0,
                                            y: 0,
                                            width: kControlWH,
                                            height: kControlWH))
        img.image = UIImage(named: "AddView_close")
        img.isUserInteractionEnabled = true
        img.addGestureRecognizer(UITapGestureRecognizer(target: self,
                                                        action: #selector(removeAction(sender:))))
        return img
    }()

    
    fileprivate var originalPoint: CGPoint = .zero
    fileprivate var originalWidth: CGFloat = .zero
    fileprivate var originalHeight: CGFloat = .zero
    fileprivate var lastControlPoint: CGPoint = .zero
    
    public var maxZoomScale: CGFloat = 2.5
    public var minZoomScale: CGFloat = 0.7
    
    
    public var isActive: Bool = false {
        didSet {
            if isActive {
                removeCtrl.isHidden = false
                rotateCtrl.isHidden = false
                addGestureRecognizer(panGesture)
                addGestureRecognizer(pinchGesture)
                addGestureRecognizer(rotationGesture)
            }else {
                removeCtrl.isHidden = true
                rotateCtrl.isHidden = true
                removeGestureRecognizer(panGesture)
                removeGestureRecognizer(pinchGesture)
                removeGestureRecognizer(rotationGesture)
            }
        }
    }
    
    fileprivate lazy var tapGesture: UITapGestureRecognizer = {
        let tap = UITapGestureRecognizer(target: self, action: #selector(tapAction(sender:)))
        return tap
    }()
    fileprivate lazy var panGesture: UIPanGestureRecognizer = {
        let pan = UIPanGestureRecognizer(target: self, action: #selector(panAction(sender:)))
        pan.delegate = self
        return pan
    }()
    fileprivate lazy var pinchGesture: UIPinchGestureRecognizer = {
        let pinch = UIPinchGestureRecognizer(target: self, action: #selector(pinchAction(sender:)))
        pinch.delegate = self
        return pinch
    }()
    fileprivate lazy var rotationGesture: UIRotationGestureRecognizer = {
        let rotaion = UIRotationGestureRecognizer(target: self, action: #selector(rotationAction(sender:)))
        rotaion.delegate = self
        return rotaion
    }()
    
    var editingViewTapHandle: ((NNEditingImageView) -> ())?
    
    
    private var infoModel = NNEditingInfoModel()
    
    convenience init(infoModel: NNEditingInfoModel) {
        self.init(frame: .zero)
        self.infoModel = infoModel
    }
    
    convenience init(isText: Bool, attributeText: NSAttributedString? = nil, image: UIImage? = nil) {
        self.init(frame: .zero)
        if isText {
            self.infoModel.isContentImage = false
            self.infoModel.originalText = attributeText
        }else {
            self.infoModel.isContentImage = true
            self.infoModel.originalImage  = image
        }
    }
    
    private func getAddImageSize(image: UIImage) -> CGSize {
        let imageW = image.size.width
        let imageH = image.size.height
        
        var targetW: CGFloat = 0
        var targetH: CGFloat = 0
        let defaultWH: CGFloat = 100
        if imageW > imageH {
            targetH = defaultWH
            targetW = targetH * imageW / imageH
        }else {
            targetW = defaultWH
            targetH = targetW * imageH / imageW
        }
        targetW += kControlWH
        targetH += kControlWH
        return CGSize(width: targetW, height: targetH)
    }
    
    override func didMoveToSuperview() {
        super.didMoveToSuperview()
        
        if infoModel.isContentImage {
            guard let originalImage = self.infoModel.originalImage else { return }
            imageView.image = originalImage
            infoModel.contentImage = originalImage
            let imageSize = getAddImageSize(image: originalImage)
            infoModel.originalSize = imageSize
        }else {
            guard let originalText = self.infoModel.originalText,
            let textImage = originalText.tn_createImage(withContentInsets: .zero) else { return }
            imageView.image = textImage
            infoModel.contentImage = textImage
            infoModel.originalSize = textImage.size
        }
        // 视图本身的尺寸Size（包含内间距）
        let targetSize = CGSize(width: infoModel.originalSize.width * infoModel.scale + kControlWH,
                                height: infoModel.originalSize.height * infoModel.scale + kControlWH)
        if infoModel.center == .zero {
            if let SuperView = superview {
                infoModel.center = CGPoint(x: SuperView.frame.size.width * 0.5,
                                           y: SuperView.frame.size.height * 0.5)
            }
        }else {
            infoModel.center = infoModel.center
        }
        self.frame = CGRect(x: infoModel.center.x - targetSize.width * 0.5,
                            y: infoModel.center.y - targetSize.height * 0.5,
                            width: targetSize.width,
                            height: targetSize.height)
        
        self.imageView.frame = CGRect(x: kControlWH * 0.5,
                                      y: kControlWH * 0.5,
                                      width: frame.size.width - kControlWH,
                                      height: frame.size.height - kControlWH)
        self.removeCtrl.frame = CGRect(x: 0,
                                       y: 0,
                                       width: kControlWH,
                                       height: kControlWH)
        self.rotateCtrl.frame = CGRect(x: frame.size.width - kControlWH,
                                       y: frame.size.height - kControlWH,
                                       width: kControlWH,
                                       height: kControlWH)
    }
    
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupSubviews()
        setupData()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    
    func setupSubviews() {
        addSubview(imageView)
        addSubview(rotateCtrl)
        addSubview(removeCtrl)
        addGestureRecognizer(tapGesture)
    }
    
    func setupData() {
        originalPoint = CGPoint(x: 0.5, y: 0.5)
        originalWidth = frame.size.width
        originalHeight = frame.size.height
    }
}


// MARK: Gesture Action
extension NNEditingImageView {
    
    @objc func panAction(sender: UIPanGestureRecognizer) {
        switch sender.state {
        case .changed:
            let translation = sender.translation(in: superview)
            let tobeCenter = CGPoint(x: center.x + translation.x,
                                     y: center.y + translation.y)
            center = tobeCenter
            sender.setTranslation(.zero, in: superview)
        default:
            break
        }
    }
    
    @objc func pinchAction(sender: UIPinchGestureRecognizer) {
        
        let touchCount = sender.numberOfTouches
        if touchCount <= 1 { return }
        
        let p1 = sender.location(ofTouch: 0, in: self)
        let p2 = sender.location(ofTouch: 1, in: self)
        let newCenter = CGPoint(x: (p1.x + p2.x) * 0.5,
                                y: (p1.y + p2.y) * 0.5)
        
        originalPoint = CGPoint(x: newCenter.x / bounds.size.width,
                                y: newCenter.y / bounds.size.height)
        
        var point = convert(getRealOriginalPoint(), to: superview)
        center = point
        let scale = sender.scale
        let tobeScale = infoModel.scale * scale
        if tobeScale >= minZoomScale && tobeScale <= maxZoomScale {
            infoModel.scale = tobeScale
            transform = transform.scaledBy(x: scale, y: scale)
            updateControlScale(scaleX: scale, scaleY: scale)
        }
        point = convert(getRealOriginalPoint(), to: superview)
        center = CGPoint(x: center.x + (center.x - point.x),
                         y: center.y + (center.y - point.y))
        sender.scale = 1
    }

    @objc func rotationAction(sender: UIRotationGestureRecognizer) {
        let touchCount = sender.numberOfTouches
        if touchCount <= 1 { return }
        
        let p1 = sender.location(ofTouch: 0, in: self)
        let p2 = sender.location(ofTouch: 1, in: self)
        let newCenter = CGPoint(x: (p1.x + p2.x) * 0.5,
                                y: (p1.y + p2.y) * 0.5)
        
        originalPoint = CGPoint(x: newCenter.x / bounds.size.width,
                                y: newCenter.y / bounds.size.height)

        var point = convert(getRealOriginalPoint(), to: superview)
        center = point
        
        transform = transform.rotated(by: sender.rotation)
        sender.rotation = 0

        point = convert(getRealOriginalPoint(), to: superview)
        center = CGPoint(x: center.x + (center.x - point.x),
                         y: center.y + (center.y - point.y))
    }

    @objc func tapAction(sender: UITapGestureRecognizer) {
        isActive = !isActive
        editingViewTapHandle?(self)
    }
    
    @objc func removeAction(sender: UITapGestureRecognizer) {
        removeFromSuperview()
    }
    
    @objc func rotateControlAction(sender: UIPanGestureRecognizer) {
        if sender.state == .began {
            lastControlPoint = convert(rotateCtrl.center, to: superview)
            return
        }
        if sender.state == .ended {
            return
        }
        let controlPoint = sender.location(in: superview)
        scaleView(controlPoint: controlPoint)
        rotateView(controlPoint: controlPoint)
        lastControlPoint = controlPoint
    }
}

extension NNEditingImageView {
    
    // 获取参考坐标点
    func getRealOriginalPoint() -> CGPoint {
        return CGPoint(x: bounds.size.width * originalPoint.x,
                       y: bounds.size.height * originalPoint.y)
    }
    
    // 计算两点之间的距离
    func distance(start: CGPoint, end: CGPoint) -> CGFloat {
        let x: CGFloat = start.x - end.x
        let y: CGFloat = start.y - end.y
        return sqrt(x * x + y * y)
    }
    
    // 控制按钮保持大小不变
    func updateControlScale(scaleX: CGFloat, scaleY: CGFloat) {
        removeCtrl.transform = removeCtrl.transform.scaledBy(x: 1.0 / scaleX,
                                                             y: 1.0 / scaleY)
        rotateCtrl.transform = rotateCtrl.transform.scaledBy(x: 1.0 / scaleX,
                                                             y: 1.0 / scaleY)
    }

    // 等比缩放
    func scaleView(controlPoint: CGPoint) {
        var point = convert(getRealOriginalPoint(), to: superview)
        center = point
        
        // 上一个控制点距离中心的距离
        let preDistance = distance(start: center, end: lastControlPoint)
        //  当前控制点距离中心的距离
        let newDistance = distance(start: center, end: controlPoint)
        let scale = newDistance / preDistance
        
        let tobeScale = infoModel.scale * scale
        
        
        if tobeScale >= minZoomScale && tobeScale <= maxZoomScale {
            infoModel.scale = tobeScale
            transform = transform.scaledBy(x: scale, y: scale)
            updateControlScale(scaleX: scale, scaleY: scale)
        }
        point = convert(getRealOriginalPoint(), to: superview)
        center = CGPoint(x: center.x + (center.x - point.x),
                         y: center.y + (center.y - point.y))
    }

    // 旋转
    func rotateView(controlPoint: CGPoint) {
        var point = convert(getRealOriginalPoint(), to: superview)
        center = CGPoint(x: center.x - (center.x - point.x),
                         y: center.y - (center.y - point.y))
        
        var angle = atan2(center.y - controlPoint.y,
                          controlPoint.x - center.x)
        let lastAngle = atan2(center.y - lastControlPoint.y,
                              lastControlPoint.x - center.x)
        angle = -angle + lastAngle
        transform = transform.rotated(by: angle)
        
        point = convert(getRealOriginalPoint(), to: superview)
        center = CGPoint(x: center.x + (center.x - point.x),
                         y: center.y + (center.y - point.y))
    }
}


// MARK: UIGestureRecognizerDelegate
extension NNEditingImageView: UIGestureRecognizerDelegate {
    
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
    
    
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        if gestureRecognizer.view == self {
            if self.rotateCtrl.frame.contains(touch.location(in: self)) {
                return false
            }
        }
        return true
    }
}
